/*
 * Copyright 2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package jp.co.cij.grails.scaffolding

import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.codehaus.groovy.grails.commons.GrailsDomainClass
import com.google.api.translate.Language
import com.google.api.translate.Translate
import org.codehaus.groovy.grails.commons.ConfigurationHolder
/**
 * generate and transrate messages
 * 
 * @author Shiro Kasahara
 */
class GrailsMessageTemplateGenerator {

    static final Log LOG = LogFactory.getLog(GrailsMessageTemplateGenerator.class)

    /**
     * ドメインクラスの定義からメッセージ定義ファイルを生成する.<br>
     * メッセージ定義ファイルが存在する場合、対象のドメインクラスのキーを上書きする
     * @param dc ドメインクラス
     * @param i18nDir i18nディレクトリ
     * @param lang 言語コード
     */
    private generateMessage(dc, i18nDir, lang) {
        def file = new File("${i18nDir}/scaffold-ex${lang ? '_' + lang : ''}.properties")
        def props
        if (!file.exists()) {
            props = createMessageTemplate(i18nDir, lang)
        }
        else {
            props = loadMessageTemplate(file)
        }

        def dcName = dc.propertyName
        def keyPrefix = "${dcName}."
        props.keySet().findAll({it?.toString().startsWith(keyPrefix)}).each { key ->
        	props.remove(key)
        }

        def naturalName = dc.naturalName
        props."${dcName}.create" = translate("Create ${naturalName}", lang)
        props."${dcName}.edit" = translate("Edit ${naturalName}", lang)
        props."${dcName}.new" = translate("New ${naturalName}", lang)
        props."${dcName}.show" = translate("Show ${naturalName}", lang)
        props."${dcName}.list" = translate("${naturalName} List", lang)
        props."${dcName}.search" = translate("${naturalName} Search", lang)
        props."${dcName}.created" = translate("${naturalName} _0 created", lang).replaceFirst("_0", " {0} ")
        props."${dcName}.updated" = translate("${naturalName} _0 updated", lang).replaceFirst("_0", " {0} ")
        props."${dcName}.deleted" = translate("${naturalName} _0 deleted", lang).replaceFirst("_0", " {0} ")
        props."${dcName}.not.found" = translate("${naturalName} not found with id _0", lang).replaceFirst("_0", " {0} ")

        def constrainedProperties = dc.getConstrainedProperties()
        dc.properties.each { prop ->
            def propName = prop.name
            if ("version" != propName) {
                props."${dcName}.${propName}" = translate(prop.naturalName, lang)
                constrainedProperties."$propName"?.inList?.each { obj ->
                	def message = obj.toString();
                    props."${dcName}.${propName}.${message}" = translate(message, lang)
                }
            }
        }
        storeMessageTemplate(props, file)
    }

    /**
     * 指定された言語のメッセージ定義ファイルを作成する.<br>
     * @param i18nDir PROJECT_HOME/grails-app/i18n ディレクトリ
     * @param lang 言語
     * @return メッセージ定義
     */
    private createMessageTemplate(i18nDir, lang) {
        def props = loadMessageTemplate(new File("${i18nDir}/scaffold-ex.properties"))

        def langProps = new Properties()
        props.each {k, v ->
            langProps."$k" = translate(v, lang)
        }
        storeMessageTemplate(langProps, new File("${i18nDir}/scaffold-ex_${lang}.properties"))
        langProps
    }

    /**
     * メッセージ定義ファイルを読み込む.<br>
     * @param file メッセージ定義ファイル
     * @return メッセージ定義
     */
    private loadMessageTemplate(file) {
        def props = new Properties()
        def fis = null
        try {
            fis = new FileInputStream(file)
            props.load(fis)
            props.each { k, v ->
                props."$k" = new String(v.getBytes("ISO-8859-1"), "UTF-8")
            }
        }
        finally {
            fis?.close()
        }
        props
    }

    /**
     * メッセージ定義ファイルを保存する.<br>
     * @param props メッセージ定義
     * @param file メッセージ定義ファイル
     */
    private storeMessageTemplate(props, file) {
        def pw = null
        try {
            pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))
            props.keySet().collect({it.toString()}).sort().each { key ->
                pw.println("${key}=${props[key]}")
            }
        }
        finally {
            pw?.close()
        }

    }

    /**
     * メッセージを翻訳する.<br>
     * 対応していない言語が指定された場合はメッセージをそのまま返す.
     * @param message メッセージ
     * @param lang 言語
     */
    private translate(message, lang) {
        if (lang && Language.validLanguages.contains(lang) && lang != Language.ENGLISH) {
            return Translate.translate(message, Language.ENGLISH, lang)
        }
        return message
    }

    /**
     * ドメインクラスの定義からメッセージ定義ファイルを生成する.<br>
     * @param dc ドメインクラス]
     * @param baseDir プロジェクトホーム
     */
    void generateI18n(dc, baseDir) {
        def langs = ConfigurationHolder.config.scaffolding.langs
        
        if (!langs) {
        	langs = [System.getProperty("user.language")]
        }
        else if (langs instanceof String) {
        	langs = [langs]
        }
        else if (langs instanceof List) {
        	langs = langs
        }
        else {
        	return
        }

        generateMessage(dc, "${baseDir}/grails-app/i18n", null)
        (langs - Language.ENGLISH).each { lang ->
            generateMessage(dc, "${baseDir}/grails-app/i18n", lang)
        }
    }
}